﻿using System;
using System.Collections.Generic;
using System.Text;

using MyLibrary.ThreeLayer.DataAccess.Interface;
using MyLibrary.ThreeLayer.DataAccess.Enum;
using MyLibrary.ThreeLayer.DataAccess.Provider.SQLParser;
using MyLibrary.ThreeLayer.DataAccess.MetaData;

namespace MyLibrary.ThreeLayer.DataAccess.QueryLanguage
{
    public abstract class QueryField : IQueryField
    {
        internal FunctionType _Function = FunctionType.None;

        protected QueryField()
        {
        }

        public abstract string FieldName { get; }
        public abstract Type TargetType { get; }
    }

    public abstract class BaseQueryField<T> : QueryField where T : class, new()
    {
        private string _fieldName;

        public override string FieldName
        {
            get { return this._fieldName; }
        }

        public override Type TargetType
        {
            get { return typeof(T); }
        }

        public ConditionExpression IsNull
        {
            get { return this.CreateExpression(ConditionOperator.IsNull, null); }
        }

        public BaseQueryField(string name)
        {
            this._fieldName = name;
        }

        protected ConditionExpression CreateExpression(ConditionOperator op, object value)
        {
            ConditionExpression expression = new ConditionExpression();
            expression.ConditionCollection.Add(new Condition(typeof(T), this._fieldName, op, value));
            return expression;
        }

        public override int GetHashCode()
        {
            return 0;
        }

    }

    public abstract class QueryExpression
    {
        internal readonly IList<QueryExpression> SqlList;
        internal abstract SqlToken SQLToken { get; }


        internal QueryExpression(IList<QueryExpression> sqlList)
        {
            this.SqlList = sqlList;
            this.SqlList.Add(this);
        }

        public virtual string ToSQL()
        {
            return this.SQLToken.ToString();
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            foreach (QueryExpression expression in this.SqlList)
                builder.Append(expression.ToSQL());
            return builder.ToString();
        }
    }

    public abstract class UnionableQueryExpression : QueryExpression
    {
        public UnionableQueryExpression(IList<QueryExpression> sqlList)
            : base(sqlList)
        {

        }

        public Union Union(QueryExpression expr)
        {
            return new Union(base.SqlList, expr);
        }
    }

    public class QueryField<T> : BaseQueryField<T> where T : class, new()
    {
        public QueryField(string name) : base(name)
        {
        }

        public ConditionExpression Between(object minValue, object maxValue)
        {
            return base.CreateExpression(ConditionOperator.Between, new object[] { minValue, maxValue });
        }

        public ConditionExpression Equal(object value)
        {
            return base.CreateExpression(ConditionOperator.Equal, value);
        }

        public ConditionExpression In(params object[] param)
        {
            return base.CreateExpression(ConditionOperator.In, param);
        }

        public ConditionExpression LessEqual(object value)
        {
            return base.CreateExpression(ConditionOperator.LessEqual, value);
        }

        public ConditionExpression LessThen(object value)
        {
            return base.CreateExpression(ConditionOperator.LessThan, value);
        }

        public ConditionExpression Like(object value)
        {
            return base.CreateExpression(ConditionOperator.Like, value);
        }

        public ConditionExpression MoreEqual(object value)
        {
            return base.CreateExpression(ConditionOperator.MoreEqual, value);
        }

        public ConditionExpression MoreThen(object value)
        {
            return base.CreateExpression(ConditionOperator.MoreThan, value);
        }

        public ConditionExpression NotBetween(object minValue, object maxValue)
        {
            return base.CreateExpression(ConditionOperator.NotBetween, new object[] { minValue, maxValue });
        }

        public ConditionExpression NotEqual(object value)
        {
            return base.CreateExpression(ConditionOperator.NotEqual, value);
        }

        public ConditionExpression NotIn(params object[] param)
        {
            return base.CreateExpression(ConditionOperator.NotIn, param);
        }

        public ConditionExpression NotLike(object value)
        {
            return base.CreateExpression(ConditionOperator.NotLike, value);
        }

        public static ConditionExpression operator ==(QueryField<T> q, object value)
        {
            return q.Equal(value);
        }

        public static ConditionExpression operator >(QueryField<T> q, object value)
        {
            return q.MoreThen(value);
        }

        public static ConditionExpression operator >=(QueryField<T> q, object value)
        {
            return q.MoreEqual(value);
        }

        public static ConditionExpression operator !=(QueryField<T> q, object value)
        {
            return q.NotEqual(value);
        }

        public static ConditionExpression operator <(QueryField<T> q, object value)
        {
            return q.LessThen(value);
        }

        public static ConditionExpression operator <=(QueryField<T> q, object value)
        {
            return q.LessEqual(value);
        }
    }

    public class QueryFieldException : Exception
    {
        public QueryFieldException(string message) : base(message) { }
    }

    public class QueryExpressionConvert : IQueryExpressionConvertor
    {
        private ProviderType _providerName;

        public QueryExpressionConvert(ProviderType provider)
        {
            this._providerName = provider;
        }

        public string Parser(ConditionExpression condition, IDictionary<string, object> paramList)
        {
            int index = 0;
            StringBuilder builder = new StringBuilder();
            OperatorParserFactory instance = OperatorParserFactory.GetInstance(this._providerName);

            foreach (Condition cdi in condition)
            {
                if (cdi._ConditionOperator == ConditionOperator.Or || cdi._ConditionOperator == ConditionOperator.And)
                {
                    if (index == 0) continue;

                    builder.Append(" ")
                        .Append(cdi._ConditionOperator.ToString())
                        .Append(" ");
                }
                else if (cdi._ConditionOperator == ConditionOperator.RightBracket)
                    builder.Append(" (");
                else if (cdi._ConditionOperator == ConditionOperator.LeftBracket)
                    builder.Append(")");
                else
                {
                    IOperatorParser parser = instance.GetParser(cdi._ConditionOperator);
                    if (parser == null) continue;

                    MappingCollection mappingCollection = MetaDataFactory.GetMappingCollection(cdi._TargetType);
                    string columnName = mappingCollection.GetColumnName(cdi._FieldName);
                    if (String.IsNullOrEmpty(columnName))
                        throw new ArgumentNullException(cdi._TargetType.FullName + "不存在字段:" + cdi._FieldName);
                    builder.Append(parser.Parser(mappingCollection._TableName, columnName, index, cdi._ConditionValue, paramList));
                    index++;
                }
            }
            return builder.ToString();
        }
    }

    public class QueryExpressionConvertFactory
    {
        public static IQueryExpressionConvertor GetQueryExpressionConvertor(ProviderType provider)
        {
            return new QueryExpressionConvert(provider);
        }
    }


}
